package cinema;

import java.util.*;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.text.SimpleDateFormat;
import java.text.ParseException;
import java.time.Instant;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.temporal.WeekFields;
import java.util.Date;
import java.util.Calendar;

public class CinemaSystem {
    private final List<User> users;
    private final List<Movie> movies;
    private final List<Schedule> schedules;
    private final List<Hall> halls;
    private final List<Log> logs;
    private final List<Ticket> tickets;
    private final Scanner scanner;

    public CinemaSystem() {
        this.scanner = new Scanner(System.in);
        this.users = initializeUsers();
        this.halls = initializeHalls();
        this.movies = initializeMovies();
        this.schedules = new ArrayList<>();
        this.logs = new ArrayList<>();
        this.tickets = new ArrayList<>();
    }

    // 启动系统
    public void start() {
        System.out.println("=== Jerry电影院管理系统 ===");
        displayLoginMenu();
    }

    // 显示登录菜单
    private void displayLoginMenu() {
        while (true) {
            System.out.println("\n请选择登录角色：");
            System.out.println("1. 管理员");
            System.out.println("2. 经理");
            System.out.println("3. 前台");
            System.out.println("4. 退出系统");
            System.out.print("请输入选项：");

            int choice = getIntInput();
            if (choice == 4) {
                System.out.println("感谢使用系统，再见！");
                return;
            }

            String role;
            switch (choice) {
                case 1:
                    role = "管理员";
                    break;
                case 2:
                    role = "经理";
                    break;
                case 3:
                    role = "前台";
                    break;
                default:
                    System.out.println("无效选项，请重新输入");
                    continue; // 跳过当前迭代，重新开始循环
            }
            authenticateUser(role);
        }
    }

    /*private void displayLoginMenu() {
        while (true) {
            System.out.println("\n请选择登录角色：");
            System.out.println("1. 管理员");
            System.out.println("2. 经理");
            System.out.println("3. 前台");
            System.out.println("4. 退出系统");
            System.out.print("请输入选项：");

            int choice = getIntInput();
            if (choice == 4) {
                System.out.println("感谢使用系统，再见！");
                return;
            }

            String role = switch (choice) {
                case 1 -> "管理员";
                case 2 -> "经理";
                case 3 -> "前台";
                default -> {
                    System.out.println("无效选项，请重新输入");

                }continue;
            };
            authenticateUser(role);
        }
    }*/

    // 用户认证
    private void authenticateUser(String role) {
        System.out.println("\n=== " + role + "登录 ===");
        System.out.print("请输入用户名：");
        String username = scanner.nextLine();
        System.out.print("请输入密码：");
        String password = scanner.nextLine();

        Optional<User> user = users.stream()
                .filter(u -> u.getUsername().equals(username) &&
                        u.getPassword().equals(password) &&
                        u.getUserType().equals(role))
                .findFirst();

        if (user.isPresent()) {
            System.out.println("登录成功，欢迎" + role + " " + username);
            showRoleMenu(user.get());
        } else {
            System.out.println("用户名、密码或角色错误，请重新登录");
        }
    }

    // 显示角色菜单
    private void showRoleMenu(User user) {
        switch (user.getUserType()) {
            case "管理员" -> showAdminMenu((Admin) user);
            case "经理" -> showManagerMenu((Manager) user);
            case "前台" -> showReceptionistMenu((Receptionist) user);
        }
    }

    //============ 管理员菜单功能 ============//
    private void showAdminMenu(Admin admin) {
        while (true) {
            System.out.println("\n=== 管理员菜单 ===");
            System.out.println("1. 添加用户");
            System.out.println("2. 删除用户");
            System.out.println("3. 列出所有用户");
            System.out.println("4. 查询用户");
            System.out.println("5. 重置用户密码");
            System.out.println("6. 修改用户信息");
            System.out.println("7. 退出登录");
            System.out.print("请输入选项：");

            int choice = getIntInput();
            switch (choice) {
                case 1 -> admin.addUser(users, scanner);
                case 2 -> {
                    System.out.print("请输入要删除的用户名：");
                    admin.deleteUser(users, scanner, scanner.nextLine());
                }
                case 3 -> admin.listAllUsers(users);
                case 4 -> {
                    System.out.println("请选择查询条件：1.用户ID 2.用户名");
                    int condition = getIntInput();
                    System.out.print("请输入查询值：");
                    String value = scanner.nextLine();
                    admin.queryUser(users, condition == 1 ? "用户ID" : "用户名", value);
                }
                case 5 -> {
                    System.out.print("请输入要重置密码的用户名：");
                    admin.resetPassword(users, scanner.nextLine());
                }
                case 6 -> {
                    System.out.print("请输入要修改的用户名：");
                    admin.modifyUserInfo(users, scanner, scanner.nextLine());
                }
                case 7 -> {
                    admin.logout();
                    return;
                }
                default -> System.out.println("无效选项，请重新输入");
            }
        }
    }

    //============ 经理菜单功能 ============//
    private void showManagerMenu(Manager manager) {
        while (true) {
            System.out.println("\n=== 经理菜单 ===");
            System.out.println("1. 影片管理");
            System.out.println("2. 场次管理");
            System.out.println("3. 查看销售数据");
            System.out.println("4. 重置前台密码");
            System.out.println("5. 退出登录");
            System.out.print("请输入选项：");

            int choice = getIntInput();
            switch (choice) {
                case 1 -> manageMovies(manager);
                case 2 -> manageSchedules(manager);
                case 3 -> manager.viewTodaySales(tickets);
                case 4 -> {
                    System.out.print("请输入要重置密码的前台用户名：");
                    manager.resetReceptionistPassword(users, scanner.nextLine());
                }
                case 5 -> {
                    manager.logout();
                    return;
                }
                default -> System.out.println("无效选项，请重新输入");
            }
        }
    }

    // 影片管理子菜单
    private void manageMovies(Manager manager) {
        while (true) {
            System.out.println("\n=== 影片管理 ===");
            System.out.println("1. 添加影片");
            System.out.println("2. 修改影片信息");
            System.out.println("3. 删除影片");
            System.out.println("4. 查询影片");
            System.out.println("5. 列出所有影片");
            System.out.println("6. 返回上级菜单");
            System.out.print("请输入选项：");

            int choice = getIntInput();
            switch (choice) {
                case 1 -> manager.addMovie(movies, scanner);
                case 2 -> {
                    System.out.print("请输入要修改的影片名称：");
                    manager.modifyMovie(movies, scanner.nextLine());
                }
                case 3 -> {
                    System.out.print("请输入要删除的影片名称：");
                    manager.deleteMovie(movies, scanner.nextLine(), schedules);
                }
                case 4 -> {
                    System.out.println("请选择查询条件：1.片名 2.导演 3.主演");
                    int condition = getIntInput();
                    System.out.print("请输入查询值：");
                    String value = scanner.nextLine();
                    manager.queryMovie(movies,
                            switch (condition) {
                                case 1 -> "片名";
                                case 2 -> "导演";
                                case 3 -> "主演";
                                default -> "片名";
                            }, value);
                }
                case 5 -> manager.listAllMovies(movies);
                case 6 -> { return; }
                default -> System.out.println("无效选项，请重新输入");
            }
        }
    }

    // 场次管理子菜单
    private void manageSchedules(Manager manager) {
        while (true) {
            System.out.println("\n=== 场次管理 ===");
            System.out.println("1. 添加场次");
            System.out.println("2. 修改场次信息");
            System.out.println("3. 删除场次");
            System.out.println("4. 列出场次");
            System.out.println("5. 自动排片");
            System.out.println("6. 返回上级菜单");
            System.out.print("请输入选项：");

            int choice = getIntInput();
            switch (choice) {
                case 1 -> addSchedule(manager);
                case 2 -> modifySchedule(manager);
                case 3 -> deleteSchedule(manager);
                case 4 -> listSchedules(manager);
                case 5 -> autoSchedule(manager);
                case 6 -> { return; }
                default -> System.out.println("无效选项，请重新输入");
            }
        }
    }

    // 添加场次
    private void addSchedule(Manager manager) {
        System.out.println("请选择影片：");
        listItems(movies, Movie::getName);
        int movieIndex = getIntInput() - 1;
        if (invalidIndex(movieIndex, movies)) return;

        System.out.println("请选择影厅：");
        listItems(halls, Hall::getHallName);
        int hallIndex = getIntInput() - 1;
        if (invalidIndex(hallIndex, halls)) return;

        System.out.println("请输入放映时间（格式：yyyy-MM-dd HH:mm）：");
        Date showTime = parseDate(scanner.nextLine());

        System.out.println("请输入票价：");
        double price = getDoubleInput();

        manager.addSchedule(
                schedules,
                movies.get(movieIndex),
                halls.get(hallIndex),
                showTime,
                price
        );
    }

    // 修改场次
    private void modifySchedule(Manager manager) {
        System.out.print("请输入要修改的场次ID：");
        Schedule schedule = findScheduleById(scanner.nextLine());
        if (schedule == null) {
            System.out.println("未找到该场次");
            return;
        }

        System.out.println("当前场次信息：");
        System.out.println("影片：" + schedule.getMovie().getName());
        System.out.println("影厅：" + schedule.getHall().getHallName());
        System.out.println("时间：" + schedule.getTime());
        System.out.println("票价：" + schedule.getPrice());

        System.out.println("请选择修改内容：1.影片 2.影厅 3.时间 4.票价");
        int choice = getIntInput();

        switch (choice) {
            case 1 -> {
                System.out.println("请选择新影片：");
                listItems(movies, Movie::getName);
                int index = getIntInput() - 1;
                if (!invalidIndex(index, movies)) {
                    schedule.setMovie(movies.get(index));
                    System.out.println("影片修改成功");
                }
            }
            case 2 -> {
                System.out.println("请选择新影厅：");
                listItems(halls, Hall::getHallName);
                int index = getIntInput() - 1;
                if (!invalidIndex(index, halls)) {
                    if (hasSoldTickets(schedule)) {
                        System.out.println("该场次已有售票，不能修改影厅");
                    } else {
                        schedule.setHall(halls.get(index));
                        System.out.println("影厅修改成功");
                    }
                }
            }
            case 3 -> {
                System.out.println("请输入新放映时间（格式：yyyy-MM-dd HH:mm）：");
                schedule.setTime(parseDate(scanner.nextLine()));
                System.out.println("时间修改成功");
            }
            case 4 -> {
                System.out.println("请输入新票价：");
                schedule.setPrice(getDoubleInput());
                System.out.println("票价修改成功");
            }
            default -> System.out.println("无效选择");
        }
    }

    // 删除场次
    private void deleteSchedule(Manager manager) {
        System.out.print("请输入要删除的场次ID：");
        Schedule schedule = findScheduleById(scanner.nextLine());
        if (schedule == null) {
            System.out.println("未找到该场次");
            return;
        }

        if (hasSoldTickets(schedule)) {
            System.out.println("该场次已有售票，不能删除");
            return;
        }

        System.out.println("确定要删除该场次吗？(y/n)");
        if ("y".equalsIgnoreCase(scanner.nextLine())) {
            schedules.remove(schedule);
            System.out.println("场次删除成功");
        } else {
            System.out.println("取消删除");
        }
    }

    // 列出场次
    private void listSchedules(Manager manager) {
        System.out.println("请选择列出方式：");
        System.out.println("1. 全部场次");
        System.out.println("2. 今日场次");
        System.out.println("3. 本周场次");
        System.out.println("4. 本月场次");
        int choice = getIntInput();

        List<Schedule> filteredSchedules = filterSchedules(choice);
        if (filteredSchedules.isEmpty()) {
            System.out.println("没有找到匹配的场次");
            return;
        }

        System.out.println("场次列表：");
        System.out.printf("%-15s %-20s %-15s %-20s %-10s %-10s%n",
                "场次ID", "影片名称", "影厅", "放映时间", "票价", "上座率");

        filteredSchedules.forEach(schedule -> {
            int totalSeats = schedule.getHall().getRow() * schedule.getHall().getColumn();
            int soldSeats = calculateSoldSeats(schedule);
            double occupancyRate = (double) soldSeats / totalSeats * 100;

            System.out.printf("%-15s %-20s %-15s %-20s %-10.2f %-10.2f%%%n",
                    schedule.getScheduleId(),
                    schedule.getMovie().getName(),
                    schedule.getHall().getHallName(),
                    schedule.getTime(),
                    schedule.getPrice(),
                    occupancyRate);
        });
    }

    // 自动排片
    private void autoSchedule(Manager manager) {
        System.out.println("请输入排片日期（格式：yyyy-MM-dd）：");
        Date scheduleDate = parseDate(scanner.nextLine() + " 00:00");

        List<Movie> availableMovies = movies.stream()
                .filter(Movie::isShowing)
                .sorted(Comparator.comparingDouble(Movie::getRating).reversed())
                .collect(Collectors.toList());

        if (availableMovies.isEmpty()) {
            System.out.println("没有可用的上映中影片，无法自动排片");
            return;
        }

        // 清空当日已有排片
        schedules.removeIf(s -> isSameDay(s.getTime(), scheduleDate));

        // 定义时间段和票价策略
        String[] timeSlots = {"09:00", "11:30", "14:00", "16:30", "19:00", "21:30"};
        double[] prices = {40.0, 50.0, 60.0, 50.0, 70.0, 70.0};

        int movieIndex = 0;
        for (Hall hall : halls) {
            for (int i = 0; i < timeSlots.length; i++) {
                Date showTime = parseDate(formatDate(scheduleDate) + " " + timeSlots[i]);
                Movie movie = availableMovies.get(movieIndex % availableMovies.size());

                Schedule newSchedule = new Schedule(
                        generateScheduleId(),
                        movie,
                        hall,
                        showTime,
                        prices[i]
                );
                schedules.add(newSchedule);
                System.out.println("已为" + hall.getHallName() + "安排" +
                        movie.getName() + " " + timeSlots[i] + "场次");
                movieIndex++;
            }
        }
        System.out.println("自动排片完成，共生成" + (halls.size() * timeSlots.length) + "个场次");
    }

    //============ 前台菜单功能 ============//
    private void showReceptionistMenu(Receptionist receptionist) {
        while (true) {
            System.out.println("\n=== 前台菜单 ===");
            System.out.println("1. 影片查询");
            System.out.println("2. 场次查询");
            System.out.println("3. 查看座位状态");
            System.out.println("4. 售票");
            System.out.println("5. 退票");
            System.out.println("6. 退出登录");
            System.out.print("请输入选项：");

            int choice = getIntInput();
            switch (choice) {
                case 1 -> listMovies(receptionist);
                case 2 -> receptionist.listAllSchedules(schedules);
                case 3 -> checkSeats(receptionist);
                case 4 -> sellTicket(receptionist);
                case 5 -> refundTicket(receptionist);
                case 6 -> {
                    receptionist.logout();
                    return;
                }
                default -> System.out.println("无效选项，请重新输入");
            }
        }
    }

    // 列出影片
    private void listMovies(Receptionist receptionist) {
        System.out.println("=== 影片列表 ===");
        movies.forEach(movie -> System.out.println(movie.getMovieInfo()));
    }

    // 查看座位
    private void checkSeats(Receptionist receptionist) {
        System.out.println("请输入场次ID：");
        Schedule schedule = findScheduleById(scanner.nextLine());
        if (schedule != null) {
            receptionist.viewSeatsStatus(schedule);
        } else {
            System.out.println("未找到该场次");
        }
    }

    // 售票
    private void sellTicket(Receptionist receptionist) {
        System.out.println("请输入场次ID：");
        String scheduleId = scanner.nextLine();
        System.out.println("请输入座位（格式：3排5号，多个座位用逗号分隔）：");
        List<String> seats = Arrays.asList(scanner.nextLine().split(","));

        Ticket ticket = receptionist.sellTicket(schedules, scheduleId, seats);
        if (ticket != null) {
            tickets.add(ticket);
        }
    }

    // 退票
    private void refundTicket(Receptionist receptionist) {
        System.out.println("请输入票号：");
        String ticketId = scanner.nextLine();
        if (receptionist.refundTicket(tickets, ticketId, schedules)) {
            Log log = new Log("退票操作，票号：" + ticketId, receptionist.getUsername());
            logs.add(log);
        }
    }

    //============ 辅助方法 ============//
    private List<User> initializeUsers() {
        List<User> users = new ArrayList<>();
        Date now = new Date();
        users.add(new Admin("1", "admin", "ynuinfo#777", now, "管理员", "12345678901"));
        users.add(new Manager("2", "manager", "123456", now, "经理", "11223344556"));
        users.add(new Receptionist("3", "reception", "123456", now, "前台", "11122233344"));
        return users;
    }

    private List<Hall> initializeHalls() {
        return Arrays.asList(
                new Hall("黄金厅", 8, 10),
                new Hall("白银厅", 10, 12),
                new Hall("翡翠厅", 7, 8),
                new Hall("钻石厅", 7, 8),
                new Hall("宝石厅", 8, 9)
        );
    }

    private List<Movie> initializeMovies() {
        return Arrays.asList(
                new Movie("000", "0", "m,n,q",
                        "镜花水月", 194, 9.5),
                new Movie("AAA", "1", "a,b,c",
                        "铁男历险记", 143, 8.8),
                new Movie("？？？", "2", "e,f",
                        "牛马幻想", 117, 9.2)
        );
    }

    // 日期相关方法
    // 日期处理方法
    private Date parseDate(String dateStr) {
        try {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
            return sdf.parse(dateStr);
        } catch (ParseException e) {
            System.out.println("日期格式错误，使用当前时间");
            return new Date();
        }
    }

    private String formatDate(Date date) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        return sdf.format(date);
    }

    // 场次过滤
    private List<Schedule> filterSchedules(int choice) {
        Date now = new Date();
        return schedules.stream()
                .filter(schedule -> switch (choice) {
                    case 2 -> isSameDay(schedule.getTime(), now);
                    case 3 -> isSameWeek(schedule.getTime(), now);
                    case 4 -> isSameMonth(schedule.getTime(), now);
                    default -> true;
                })
                .collect(Collectors.toList());
    }

    private boolean isSameDay(Date time, Date now) {
        if (time == null || now == null) return false;
        Calendar cal1 = Calendar.getInstance();
        Calendar cal2 = Calendar.getInstance();
        cal1.setTime(time);
        cal2.setTime(now);
        return cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR) &&
                cal1.get(Calendar.MONTH) == cal2.get(Calendar.MONTH) &&
                cal1.get(Calendar.DAY_OF_MONTH) == cal2.get(Calendar.DAY_OF_MONTH);
    }

    private boolean isSameWeek(Date time, Date now) {
        if (time == null || now == null) return false;
        Calendar cal1 = Calendar.getInstance();
        Calendar cal2 = Calendar.getInstance();
        cal1.setTime(time);
        cal2.setTime(now);
        cal1.setFirstDayOfWeek(Calendar.MONDAY);
        cal2.setFirstDayOfWeek(Calendar.MONDAY);
        return cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR) &&
                cal1.get(Calendar.WEEK_OF_YEAR) == cal2.get(Calendar.WEEK_OF_YEAR);
    }

    private boolean isSameMonth(Date time, Date now) {
        if (time == null || now == null) return false;
        Calendar cal1 = Calendar.getInstance();
        Calendar cal2 = Calendar.getInstance();
        cal1.setTime(time);
        cal2.setTime(now);
        return cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR) &&
                cal1.get(Calendar.MONTH) == cal2.get(Calendar.MONTH);
    }
   /* private List<Schedule> filterSchedules(int choice) {
        Date now = new Date();
        return schedules.stream()
                .filter(schedule -> switch (choice) {
                    case 2 -> isSameDay(schedule.getTime(), now);
                    case 3 -> isSameWeek(schedule.getTime(), now);
                    case 4 -> isSameMonth(schedule.getTime(), now);
                    default -> true;
                })
                .collect(Collectors.toList());
    }

    private boolean isSameMonth(Date time, Date now) {
    }

    private boolean isSameWeek(Date time, Date now) {
    }

    private boolean isSameDay(Date time, Date now) {
    }*/

    // 计算已售座位
    private int calculateSoldSeats(Schedule schedule) {
        return (int) tickets.stream()
                .filter(t -> t.getSchedule().getScheduleId().equals(schedule.getScheduleId()) &&
                        !t.isRefunded())
                .flatMap(t -> Arrays.stream(t.getSeat().split(",")))
                .count();
    }

    // 检查场次是否有售票
    private boolean hasSoldTickets(Schedule schedule) {
        return tickets.stream()
                .anyMatch(t -> t.getSchedule().getScheduleId().equals(schedule.getScheduleId()) &&
                        !t.isRefunded());
    }

    // 查找场次
    private Schedule findScheduleById(String id) {
        return schedules.stream()
                .filter(s -> s.getScheduleId().equals(id))
                .findFirst()
                .orElse(null);
    }

    // 生成场次ID
    private String generateScheduleId() {
        return "SCH" + System.currentTimeMillis() + schedules.size();
    }

    // 通用辅助方法
    private int getIntInput() {
        try {
            return Integer.parseInt(scanner.nextLine());
        } catch (NumberFormatException e) {
            System.out.println("请输入有效数字");
            return -1;
        }
    }

    private double getDoubleInput() {
        try {
            return Double.parseDouble(scanner.nextLine());
        } catch (NumberFormatException e) {
            System.out.println("请输入有效数字");
            return 0.0;
        }
    }

    private <T> void listItems(List<T> items, java.util.function.Function<T, String> mapper) {
        for (int i = 0; i < items.size(); i++) {
            System.out.println((i + 1) + ". " + mapper.apply(items.get(i)));
        }
    }

    private <T> boolean invalidIndex(int index, List<T> list) {
        if (index < 0 || index >= list.size()) {
            System.out.println("无效选择");
            return true;
        }
        return false;
    }}

    /*// 简化日期处理（实际项目中应使用SimpleDateFormat）
    private Date parseDate(String dateStr) {
        // 简化实现，实际项目应使用日期解析
        return new Date();
    }

    private String formatDate(Date date) {
        // 简化实现，实际项目应使用日期格式化
        return "";
    }
}*/